package com.zy.ems.common.http;

import java.io.File;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.client.RestTemplate;

/**
 * http请求工具类。
 * 
 * @author Luffy
 *
 */
public class HttpClientUtil {
	private static Logger LOG = LoggerFactory.getLogger(HttpClientUtil.class);

	private static final int DEFAULT_MAX_TOTAL_CONNECTIONS = 1000;

	private static final int DEFAULT_MAX_CONNECTIONS_PER_ROUTE = 200;

	/**
	 * httpClient客户端
	 */
	private static CloseableHttpClient httpClient;

	/**
	 * 连接池管理器
	 */
	private static PoolingHttpClientConnectionManager connManager;

	/**
	 * Spring提供的访问Rest服务的客户端
	 */
	private static RestTemplate restTemplate;

	/**
	 * 初始化
	 */
	static {
		// 连接池管理器
		connManager = new PoolingHttpClientConnectionManager();
		// 连接池最大连接数
		connManager.setMaxTotal(DEFAULT_MAX_TOTAL_CONNECTIONS);
		// 每个路由最大连接数
		connManager.setDefaultMaxPerRoute(DEFAULT_MAX_CONNECTIONS_PER_ROUTE);

		// http请求配置信息
		RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(50000).setSocketTimeout(50000)
				.setConnectionRequestTimeout(50000).setCookieSpec(CookieSpecs.STANDARD).build();

		httpClient = HttpClients.custom().setConnectionManager(connManager).setDefaultRequestConfig(requestConfig)
				.setConnectionManagerShared(true).build();
		LOG.info("Initializing CloseableHttpClient");

		// 添加内容转换器
		List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
		messageConverters.add(new StringHttpMessageConverter(StandardCharsets.UTF_8));
		messageConverters.add(new FormHttpMessageConverter());
		messageConverters.add(new MappingJackson2HttpMessageConverter());

		restTemplate = new RestTemplate(new HttpComponentsClientHttpRequestFactory(httpClient));
		restTemplate.setMessageConverters(messageConverters);
		LOG.info("Initializing RestTemplate");
	}

	static CloseableHttpClient getHttpClient() {
		return httpClient;
	}

	static RestTemplate getRestTemplate() {
		return restTemplate;
	}

	/**
	 * 处理GET请求。
	 * 
	 * @param url
	 * @return
	 */
	public static String executeGet(String url) {
		return executeGet(url, null);
	}

	/**
	 * 处理GET请求。
	 * 
	 * @param url
	 * @param params
	 * @return
	 */
	public static String executeGet(String url, Map<String, String> params) {
		return executeGet(url, null, params);
	}

	/**
	 * 处理GET请求。
	 * 
	 * @param url
	 * @param headers
	 * @param params
	 * @return
	 */
	public static String executeGet(String url, Map<String, String> headers, Map<String, String> params) {
		return execute(url, HttpGet.METHOD_NAME, headers, params, null);
	}

	/**
	 * 处理POST请求。
	 * 
	 * @param url
	 * @return
	 */
	public static String executePost(String url) throws URISyntaxException {
		return executePost(url, null);
	}

	/**
	 * 处理POST请求。
	 * 
	 * @param url
	 * @param params
	 * @return
	 */
	public static String executePost(String url, Map<String, String> params) {
		return executePost(url, null, params);
	}

	public static String executePost(String url, Map<String, String> params, Charset charSet) {
		return executePost(url, null, params, charSet);
	}

	/**
	 * 处理POST请求。
	 * 
	 * @param url
	 * @param headers
	 * @param params
	 * @return
	 */
	public static String executePost(String url, Map<String, String> headers, Map<String, String> params,
			Charset charSet) {
		return execute(url, HttpPost.METHOD_NAME, headers, params, charSet);
	}

	/**
	 * 处理POST请求。
	 * 
	 * @param url
	 * @param headers
	 * @param params
	 * @return
	 */
	public static String executePost(String url, Map<String, String> headers, Map<String, String> params) {
		return execute(url, HttpPost.METHOD_NAME, headers, params, null);
	}

	/**
	 * 上传文件。
	 * 
	 * @param url
	 * @param partName
	 * @param filePath
	 * @param params
	 * @param contentType
	 *            上传文件类型
	 * @return
	 */
	public static String uploadFile(String url, String partName, String filePath, Map<String, String> params,
			String contentType) {
		MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create();
		// 上传的文件
		File file = new File(filePath);
		FileBody fileBody = new FileBody(file, ContentType.create(contentType));
		entityBuilder.addPart(partName, fileBody);
		// 设置请求参数
		if (params != null && !params.isEmpty()) {
			for (Map.Entry<String, String> param : params.entrySet()) {
				entityBuilder.addTextBody(param.getKey(), param.getValue());
			}
		}
		// 构建http请求
		RequestBuilder requestBuilder = RequestBuilder.post(url).setCharset(Consts.UTF_8);
		// 设置请求体
		requestBuilder.setEntity(entityBuilder.build());
		// 执行http请求
		return doExecute(requestBuilder.build(), Consts.UTF_8);
	}

	/**
	 * 获得Http请求前缀。
	 * 
	 * @return
	 */
	public static String getHttpRequestPrefix() {
		return "http://back.zhen.net";
	}

	/**
	 * 处理HTTP请求。
	 * 
	 * @param uri
	 * @param method
	 * @param headers
	 * @param params
	 * @return
	 * @throws URISyntaxException
	 */
	public static String execute(String uri, String method, Map<String, String> headers, Map<String, String> params,
			Charset charSet) {
		// 模块间服务调用请求地址以“/”开头需要补全
		if (uri.startsWith("/")) {
			uri = getHttpRequestPrefix() + uri;
			LOG.info("请求的地址：" + uri);
		}
		// 字符集
		if (charSet == null) {
			charSet = Consts.UTF_8;
		}
		// 构建http请求
		RequestBuilder requestBuilder = RequestBuilder.create(method).setUri(uri).setCharset(charSet);
		// 设置请求参数
		if (params != null && !params.isEmpty()) {
			for (Map.Entry<String, String> param : params.entrySet()) {
				requestBuilder.addParameter(param.getKey(), param.getValue());
			}
		}
		// 设置请求头
		if (headers != null && !headers.isEmpty()) {
			for (Map.Entry<String, String> header : headers.entrySet()) {
				requestBuilder.addHeader(header.getKey(), header.getValue());
			}
		}
		// 执行http请求
		return doExecute(requestBuilder.build(), charSet);
	}

	/**
	 * 执行Http请求。
	 * 
	 * @param request
	 * @return
	 */
	private static String doExecute(HttpUriRequest request, Charset charSet) {
		// 执行请求
		HttpResponse response = null;
		try {
			response = getHttpClient().execute(request);
			// 处理请求结果
			HttpEntity entity = response.getEntity();
			String result = "";
			if (entity != null) {
				result = EntityUtils.toString(entity, charSet);
			}
			LOG.info("请求执行结果：" + result);
			return result;
		} catch (Exception e) {
			LOG.error(e.getMessage(), e);
			throw new RuntimeException(e);
		}
	}

}
